package com.lyl.xxx.modules.system.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyl.xxx.modules.framework.security.utils.SecurityUtil;
import com.lyl.xxx.modules.system.account.dao.SysMenuDao;
import com.lyl.xxx.modules.system.account.entity.SysMenu;
import com.lyl.xxx.modules.system.account.service.SysMenuService;
import com.lyl.xxx.modules.web.account.model.dto.MenuDTO;
import com.lyl.xxx.modules.web.account.model.dto.MenuTreeDTO;
import com.lyl.xxx.modules.web.account.model.vo.MenuTreeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 菜单表(SysMenu)表服务实现类
 *
 * @author Mr Luo
 * @since 2022-10-09 10:09:01
 */
@Service("sysMenuService")
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenu> implements SysMenuService {
    private final SysMenuDao sysMenuDao;

    @Override
    public Set<String> getPermsByUserId(Long userId) {
        return sysMenuDao.getPermsByUserId(userId);
    }

    @Override
    public List<MenuTreeVO> menuTree(MenuTreeDTO dto) {
        //根据请求参数模糊查询菜单列表
        List<SysMenu> menuList = listByMenuNameLikeAndStatus(dto.getMenuName(), dto.getStatus());
        if (CollUtil.isEmpty(menuList)) {
            return ListUtil.empty();
        }
        //根据查询出的菜单列表生成树状菜单
        return menuTree(menuList);
    }

    @Override
    public boolean updateMenu(MenuDTO dto) {
        SysMenu menu = BeanUtil.copyProperties(dto, SysMenu.class);
        switch (menu.getMenuType()) {
            case "M":
                menu.setComponent("").setQuery("").setPerms("");
                break;
            case "F":
                menu.setComponent("").setIcon("").setPath("").setQuery("")
                        .setVisible(true).setHidden(true).setPerms("");
                break;
            default:
                break;
        }
        return saveOrUpdate(menu);
    }

    @Override
    public List<MenuTreeVO> getRouters() {
        Long userId = SecurityUtil.getSafeUserId();
        List<SysMenu> menuList = sysMenuDao.getMenuTreeByUserId(userId);
        return menuTree(menuList);
    }

    /**
     * 根据菜单列表生成菜单树
     *
     * @param menuList 菜单列表
     * @return 菜单树
     */
    private List<MenuTreeVO> menuTree(List<SysMenu> menuList) {
        if (ObjectUtil.isEmpty(menuList)) {
            return ListUtil.empty();
        }
        Map<Integer, List<MenuTreeVO>> levelMap = menuList.stream()
                .map(this::convertToMenuTreeVo)
                .collect(Collectors.groupingBy(MenuTreeVO::getLevel));
        List<Integer> levelList = levelMap.keySet().stream().sorted().collect(Collectors.toList());
        List<MenuTreeVO> menus = ListUtil.empty();
        while (!levelList.isEmpty()) {
            Integer level = levelList.remove(levelList.size() - 1);
            List<MenuTreeVO> childMenus = levelMap.getOrDefault(level, ListUtil.empty());
            menus = levelMap.getOrDefault(level - 1, ListUtil.empty());
            if (menus.isEmpty()) {
                return childMenus.stream().sorted(Comparator.comparingInt(MenuTreeVO::getOrderNum)).collect(Collectors.toList());
            }
            Map<Long, List<MenuTreeVO>> childMap = childMenus.stream().collect(Collectors.groupingBy(MenuTreeVO::getParentId));
            menus.stream().sorted(Comparator.comparingInt(MenuTreeVO::getOrderNum)).forEach(menu -> menu.setChildren(childMap.get(menu.getMenuId())));
        }
        return menus;
    }

    /**
     * 菜单树：
     * 此方法有缺陷，对于模糊查询的数据，如果数据中不存在parentId等于0的数据，会返回空数据
     *
     * @param parentId 父级id
     * @param menuList 菜单列表
     * @return 菜单树
     */
    private List<MenuTreeVO> menuTree(Long parentId, List<SysMenu> menuList) {
        if (ObjectUtil.isEmpty(parentId) || ObjectUtil.isEmpty(menuList)) {
            return ListUtil.empty();
        }
        return menuList.stream()
                .filter(sysMenu -> ObjectUtil.equals(sysMenu.getParentId(), parentId))
                .map(this::convertToMenuTreeVo)
                .map(vo ->
                        vo.setChildren(menuTree(vo.getMenuId(), menuList)))
                .collect(Collectors.toList());
    }

    private MenuTreeVO convertToMenuTreeVo(SysMenu sysMenu) {
        return BeanUtil.copyProperties(sysMenu, MenuTreeVO.class);
    }

    /**
     * 根据菜单名称和状态进行模糊查询
     *
     * @param menuName 菜单名称
     * @param status   菜单状态
     * @return 菜单列表
     */
    private List<SysMenu> listByMenuNameLikeAndStatus(String menuName, Boolean status) {
        return lambdaQuery().like(CharSequenceUtil.isNotBlank(menuName), SysMenu::getMenuName, menuName)
                .eq(ObjectUtil.isNotEmpty(status), SysMenu::getHidden, status).list();
    }
}

